//***************************************
// mCalc 26122011
// Riku Maikola rpm@ac-mapa.org
// **************************************
#include<cmath>
#include <wx/string.h>
#include <wx/stattext.h>
#include "mSolver.h"
#include <iostream>

//****   SET VARIABLE POINTER FROM OUTSIDE CLASS****//
void mSolver::SetSolverV(double * var)
{
    V = var;
};


wxString mSolver::GetString()
{
    wxString TEXT;
    for(uint a=0; a<P.Count(); a++)
        TEXT << P[a] << _(" ");

    return TEXT;
}


double mSolver::calc(wxString str)
{
    if(str.Matches(_("-nan")))return NAN;
    if(str.Matches(_("nan")))return NAN;

    Parse(str);
    EVA();
    if(P.GetCount()>1)return NAN;
    return ToDouble(P[0]);
}

bool mSolver::IsConstant(uint a)
{
    if(P[a].at(0)>47 && P[a].at(0)<58 )
        return true;
    if(P[a].Len()>1 && P[a].GetChar(0)==45)
        return true;

    return false;
}

double mSolver::ToDouble(wxString P)
{
    double value;
    if(!P.ToDouble(&value))
    {
        return NAN;
    }
    return value;
};

void mSolver::Parse(wxString M)
{
    P.Clear();
    for(uint a=0; a<M.Len(); a++)
    {
        if(M[a]>34 && M[a]<48 || M[a]==91 || M[a]==93 || M[a]==61)
        {
            P.Add(M[a]);
            continue;
        }

        //numbers
        if(((M[a]>45) && (M[a]<58)))
        {
            wxString TEXT;
            while(((M[a]>45) && (M[a]<58)) && M[a]!=47)
            {
                TEXT << M[a];
                a++;
            }
            a--;
            P.Add(TEXT);
            continue;
        }

        //String
        if(M[a]==34)
        {
            a++;
            wxString TEXT;
            while(M[a]!=34)
            {
                if(a>=M.Len())
                {
                    P.Add(_("ERR:no end to the string"));
                    return;
                }
                TEXT << M[a];
                a++;
            }
            P.Add(TEXT);
            continue;
        }


        //Text
        if( ((M[a]>64) && (M[a]<91)) || ((M[a]>96) && (M[a]<123)) || (M[a]==95))
        {
            wxString TEXT;
            while((M[a]>64) && (M[a]<91) || (M[a]>96) && (M[a]<123) || (M[a]==95))
            {
                TEXT << M[a];
                a++;
            }
            a--;
            P.Add(TEXT);
            continue;
        }
    }
}

bool mSolver::EVA()
{


start:

//MAKROS VARIABLE HANDLER
    for(uint a=0; a<P.GetCount(); a++)
    {
        if(P[a]==_("#") && IsConstant(a+1))
        {

            if(P.GetCount()>(2+a))if(P[a+2]==_("="))continue;
            P[a] = _("");
            P[a] << wxString::Format(_("%1.10f"),V[int(ToDouble(P[a+1]))]);

            P.RemoveAt(a+1);
            continue;
        }
    }





    for(uint a=0; a<P.GetCount(); a++)
    {

        if(P[a]==_("["))
        {
            int sulkuja=0;
            wxString TEXT;
            int alku=0;
            while(P[a]!=_("]"))
            {
                if( P[a]==_("[") )
                {
                    alku=a;
                    TEXT = _("");
                }
                if(!P[a].IsSameAs(_("[")))TEXT << P[a];
                a++;
            }
            P.RemoveAt(alku,a-alku+1);

            mSolver SULKU;
            SULKU.Parse(TEXT);
            SULKU.EVA();
            P.Insert(wxString::Format(_("%1.10f"),ToDouble(SULKU.P[0])),alku);
            goto start;
            continue;
        }
    }

    //PARSING - --
    if(1<P.GetCount())
    {
        if(P[0].IsSameAs(_("-")) && IsConstant(1))
        {
            P.Insert(wxString::Format(_("%1.10f"),-ToDouble( P[1]   )),0);
            P.RemoveAt(1,2);
        }
    }

    for(uint a=0; a<P.GetCount(); a++)
    {
        if((a+2)<P.GetCount())
        {
            if(P[a].IsSameAs(_("-")) && P[a+1].IsSameAs(_("-"))  && IsConstant((a+2))     )
            {
                P.Insert(wxString::Format(_("%1.10f"),-ToDouble(P[a+2])),a+1);
                P.RemoveAt(a+2,2);
                goto start;
                continue;
            }
        }
    }

    for(uint a=0; a<P.GetCount(); a++)
    {
        if((a+2)<P.GetCount())
        {
            if((!IsConstant(a)) && P[a+1].IsSameAs(_("-"))  && IsConstant(a+2)     )
            {
                P.Insert(wxString::Format(_("-%1.10f"), ToDouble(P[a+2])   ),a+1);
                P.RemoveAt(a+2,2);
                goto start;
                continue;
            }
        }
    }

    //FUNCTIONS

    for(uint a=0; a<P.GetCount(); a++)
    {
        if(P.GetCount()==1)
            return P[0];

        //LOGIC
        if((a+2)<P.GetCount())
        {
            if(IsConstant(a) && P[a+1].IsSameAs(_("LE")) && IsConstant((a+2)))
            {
                P.Insert(wxString::Format(_("%d"),int(ToDouble( P[a])*1000) <= int(ToDouble(P[a+2])*1000))   ,a);
                P.RemoveAt(a+1,3);
                goto start;
                continue;
            }
            if(IsConstant(a) && P[a+1].IsSameAs(_("EQ")) && IsConstant((a+2)))
            {
                P.Insert(wxString::Format(_("%d"),AER((ToDouble(P[a])*1000),ToDouble(P[a+2])*1000)),a);
                P.RemoveAt(a+1,3);
                goto start;
                continue;
            }
            if(IsConstant(a) && P[a].IsSameAs(_("LT")) && IsConstant((a+2)))
            {
                P.Insert(wxString::Format(_("%d"),int(ToDouble( P[a])<ToDouble(P[a+2]))),a);
                P.RemoveAt(a+1,3);
                goto start;
                continue;
            }
            if(IsConstant(a) && P[a+1].IsSameAs(_("GT")) && IsConstant((a+2)))
            {
                P.Insert(wxString::Format(_("%d"),int(ToDouble(P[a])>ToDouble(P[a+2]))),a);
                P.RemoveAt(a+1,3);
                goto start;
                continue;
            }
        }


        if((a+1)<P.GetCount())
        {
            if(P[a].IsSameAs(_("SIN")) && IsConstant(a+1))
            {
                P.Insert(wxString::Format(_("%1.10f"), sin(DegToRad*ToDouble( P[a+1]))),a);
                P.RemoveAt(a+1,2);
                goto start;
                continue;
            }
            if(P[a].IsSameAs(_("ASIN")) && IsConstant(a+1))
            {
                P.Insert(wxString::Format(_("%1.10f"), asin(ToDouble(P[a+1])*180/PI)),a);
                P.RemoveAt(a+1,2);
                goto start;
                continue;
            }

            if(P[a].IsSameAs(_("COS")) && IsConstant(a+1))
            {
                P.Insert(wxString::Format(_("%1.10f"), cos(DegToRad*ToDouble( P[a+1]))),a);
                P.RemoveAt(a+1,2);
                goto start;
                continue;
            }
            if(P[a].IsSameAs(_("ACOS")) && IsConstant(a+1))
            {
                P.Insert(wxString::Format(_("%1.10f"), acos(ToDouble(P[a+1])*180/PI)),a);
                P.RemoveAt(a+1,2);
                goto start;
                continue;
            }
            if(P[a].IsSameAs(_("TAN")) && IsConstant(a+1))
            {
                P.Insert(wxString::Format(_("%1.10f"), tan(DegToRad*ToDouble(P[a+1]))),a);
                P.RemoveAt(a+1,2);
                goto start;
                continue;
            }
            if(P[a].IsSameAs(_("ATAN")) && IsConstant(a+1))
            {
                P.Insert(wxString::Format(_("%1.10f"), atan(ToDouble(P[a+1]))*180/PI),a);
                P.RemoveAt(a+1,2);
                goto start;
                continue;
            }

            if(P[a].IsSameAs(_("FUP")) && IsConstant(a+1))
            {
                P.Insert(wxString::Format(_("%1.10f"), ceil(ToDouble(P[a+1]))),a);
                P.RemoveAt(a+1,2);
                goto start;
                continue;
            }

            if(P[a].IsSameAs(_("SQRT")) && IsConstant(a+1))
            {
                P.Insert(wxString::Format(_("%1.10f"), sqrt(ToDouble(P[a+1]))),a);
                P.RemoveAt(a+1,2);
                goto start;
                continue;
            }
            if(P[a].IsSameAs(_("ABS")) && IsConstant(a+1))
            {
                P.Insert(wxString::Format(_("%1.10f"), abs(ToDouble(P[a+1]))),a);
                P.RemoveAt(a+1,2);
                goto start;
                continue;
            }

        }
    }
    // KERTO JAKO
    for(uint a=0; a<P.GetCount(); a++)
    {
        if(P.GetCount()==1)
            return P[0];

        if((a+2)<P.GetCount())
        {
            if(IsConstant(a) && IsConstant(a+2))
            {
                if(P[a+1].IsSameAs(_("*")))
                {
                    P.Insert(wxString::Format(_("%1.10f"),(ToDouble(P[a]) * ToDouble(P[a+2]))),a);
                    P.RemoveAt(a+1,3);
                    goto start;
                    continue;
                }
                if(P[a+1].IsSameAs(_("/")))
                {
                    P.Insert(wxString::Format(_("%1.10f"),(ToDouble(P[a]) / ToDouble(P[a+2]))),a);
                    P.RemoveAt(a+1,3);
                    goto start;
                    continue;
                }
            }
        }
    }
    // +-
    for(uint a=0; a<P.GetCount(); a++)
    {
        if(P.GetCount()==1)
            return P[0];

        if((a+2)<P.Count())
        {
            if(IsConstant(a) && IsConstant(a+2))
            {
                if(P[a+1].IsSameAs(_("+")))
                {
                    P.Insert(wxString::Format(_("%1.10f"),ToDouble(P[a]) + ToDouble(P[a+2])),a);
                    P.RemoveAt(a+1,3);
                    goto start;
                    continue;
                }
                if(P[a+1].IsSameAs(_("-")))
                {
                    P.Insert(wxString::Format(_("%1.10f"),(ToDouble(P[a]) - ToDouble(P[a+2]))),a);
                    P.RemoveAt(a+1,3);
                    goto start;
                    continue;
                }
            }
        }
    }

    //FINISH SET VALUE TO ARRAY.........
    if(P.GetCount()==4 && P[0]==_("#") && IsConstant(1) && P[2]==_("=") && IsConstant(3))
    {
        V[ int(ToDouble(P[1]))] = ToDouble(P[3]);
        P.clear();
        return true;
    }

//std::cout << GetString().mb_str() << " OUT\n";
}
